//==========================================================================
// Copyright (c) 2000-2008,  Elastos, Inc.  All Rights Reserved.
//==========================================================================
#ifndef __BULKONLY_H_
#define __BULKONLY_H_


#define CBW_SIGNATURE       0x43425355
#define CSW_SIGNATURE       0x53425355
#define BULK_CBW_SIZE       0x1F
#define BULK_CSW_SIZE       0x0D
#define MAX_CB_LEN          0x10
#define MAX_LUN             0x01
#define CBW_DATAOUT         0x00
#define CBW_DATAIN          0x80
#define CSW_STATUS_GOOD     0x00
#define CSW_STATUS_FAILED   0x01
#define CSW_STATUS_PHASE    0x02
#define CSW_DATARESIDUE_NO  0x00

#define DEFAULT_DATA_BUFFER_SIZE (4096 * 16)

#define GET_MAX_LUN        0xFE
#define BULK_ONLY_RESET    0xFF

#if defined(_INTEL) || defined(_EVC)
#undef DECL_PACKED
#define DECL_PACKED
#pragma pack(push, 1)
#endif
/* Command Block Wrapper */
typedef struct DECL_PACKED __CBbbCbw {
    UINT  dCBWSignature;
    UINT  dCBWTag;
    UINT  dCBWDataTransferLength;
    UCHAR bmCBWFlags;
    UCHAR bCBWLUN;
    UCHAR bCBWCBLentgh;
    UCHAR CBWCB[MAX_CB_LEN];
}CBbbCbw, *PCBbbCbw;

/* Command Status Wrapper */
typedef struct DECL_PACKED __CBbbCsw {
    UINT  dCSWSignature;
    UINT  dCSWTag;
    UINT  dCSWDataResidue;
    UCHAR bCSWStatus;
} CBbbCsw, *PCBbbCsw;
#if defined(_INTEL) || defined(_EVC)
#pragma pack(pop)
#endif

/* mass storage class states */
typedef enum _MSC_STATE {
    MSC_STATE_UNKNOWN = 0,
    MSC_STATE_IDLE,
    MSC_STATE_COMMAND_TRANSPORT,
    MSC_STATE_DATA_IN_TRANSPORT,
    MSC_STATE_DATA_OUT_TRANSPORT,
    MSC_STATE_STATUS_TRANSPORT,
    MSC_STATE_WAIT_FOR_RESET,
} MSC_STATE, *PMSC_STATE;

#define CBW_XFER_DATALENGTH(x) ((x)->dCBWDataTransferLength)
#define CBW_GET_CB(x)   ((x)->CBWCB)
#define CBW_CB_LENGTH(x)    ((x)->bCBWCBLentgh)
#define CBW_IS_DATAIN(x) ((((x)->bCBWFlags) & CBW_DATAIN) == CBW_DATAIN)
#define CBW_GET_SIGN(x) ((x)->dCBWSignature)

inline BOOL IsVaildCbw();
inline void SetCbw(PCBbbCbw pCbw, UCHAR *pCbwInfo);
inline void SetCsw(PCBbbCbw pCsw, UINT Tag, UINT Residue, UCHAR Status);


class CBulk {
public:
    //interface
    ECode CreateTaskThread();
    ECode TransferThread();

    ECode Bulk_Init(wchar_t *);
    ECode Bulk_DeInit();
    ECode Bulk_Start();
    ECode Bulk_Reset();
    ECode Bulk_Wake(wchar_t *);
    void    Bulk_Stop(BOOL);

    DWORD Bulk_ExecuteCB( PTRANSPORT_COMMAND  pCommand,
                          PTRANSPORT_DATA     pData );
    BOOL Bulk_HandleCbw();
    void Bulk_BuildCsw( DWORD dwCSWTag,
                        DWORD dwCSWDataResidue,
                        BYTE  bCSWStatus);
    BOOL Bulk_RecvCbw();
    void Bulk_StateChange( MSC_STATE );
    void Bulk_OpenInterface();
    UINT Bulk_SetupRx(PBYTE pbData, UINT cbData);
    UINT Bulk_SetupTx(PBYTE pbData, UINT cbData);
    void ProcessBOTransfer();
    void ProcessBITransfer();

public:
    CUsbApi *m_pUfunc;
    DzEvent m_DevEvent;
    UINT m_uDataResidue;
    MSC_STATE m_MscState;
    IThread *m_pCtrlThd;
    TRANSPORT_COMMAND m_tcCmd;
    TRANSPORT_DATA    m_tdData;
    descriptor *m_pMassDesc;
    BYTE *m_pbDataBuf;
    UINT m_cbDataBuf;
    UINT m_dwCBWTag;
    UINT m_dwCBWDataTransferLength;
    UINT m_dwCSWDataResidue;
    UINT m_dwCSWStatus;
    BYTE m_Cxw[BULK_CBW_SIZE];
    CBbbCbw *m_pCbw;
    CBbbCsw *m_pCsw;
    PIPE_INFO m_BOpipe, m_BIpipe;
public:
    BOOL m_IsInit;
};

class UmCtrl : public Driver {
    CARAPI Read(
        /* [in] */ UINT64 u64Offset,
        /* [in] */ UINT uNumberOfBytesToRead,
        /* [out] */ EzByteBuf ebbData,
        /* [out] */ IEvent * * ppCompletionEvent);

    CARAPI Write(
        /* [in] */ UINT64 u64Offset,
        /* [in] */ EzByteBuf ebbData,
        /* [out] */ UINT * puNumberOfBytesWritten,
        /* [out] */ IEvent * * ppCompletionEvent);

    CARAPI Control(
        /* [in] */ INT nControlCode,
        /* [in] */ EzByteBuf ebbInData,
        /* [out] */ EzByteBuf ebbOutData,
        /* [out] */ IEvent * * ppCompletionEvent);

    virtual void Dispose();
};

#endif //__BULKONLY_H_

